﻿using System;
using System.Collections;
using System.Collections.Generic;
using Yanesdk.Draw;

namespace ADV_Evaluator { 

    /// <summary>
    /// MySpriteを集めた、順番付きのハッシュ。スプライトのラベルでアクセスできる。
    /// SortedList&lt;string, MySprite&gt;のラッパー。
    /// </summary>
    /// <remarks>
    /// 先頭の要素からz座標が小さい順に並んでいるようにする。
    /// foreachでまわしながらBltすればz座標が反映される。
    /// </remarks>
    class SpriteList : IEnumerable {

        /// <summary>
        /// SortedListは挿入すると勝手にキーの辞書順に並び替えてしまうので、
        /// 挿入した順番どおりに格納するようにするための並び順を定義したクラス。
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        public class OrderedComparer<T> : IComparer<T> {
            /// <summary>
            /// ２つの要素を比較する。
            /// </summary>
            /// <param name="x"></param>
            /// <param name="y"></param>
            /// <returns>
            /// xがyより小さければ負、大きければ正、同じなら0を返す。
            /// 正が返ると前に、負が返ると後ろに格納される。
            /// </returns>
            public int Compare(T x, T y) {
                // 常に負を返し、最後尾へ格納
                return x.Equals(y) ? 0 : -1;
            }
        }

        /// <summary>
        /// 順番つきハッシュ
        /// </summary>
        private SortedList<string, MySprite> list;

        /// <summary>
        /// 初期化
        /// </summary>
        public SpriteList() {
            list = new SortedList<string, MySprite>(new OrderedComparer<string>());
        }

        /// <summary>
        /// 要素の個数
        /// </summary>
        public int Count {
            get { return list.Count; }
        }

        /// <summary>
        /// 各スプライトに関連付けられたラベル名を返す
        /// </summary>
        public IList<string> keys {
            get { return list.Keys; }
        }

        /// <summary>
        /// 格納されているスプライトのリストを返す。
        /// </summary>
        public IList<MySprite> Values {
            get { return list.Values; }
        }

        /// <summary>
        /// インデクサ
        /// </summary>
        /// <param name="key">スプライトに関連付けられたラベル名</param>
        /// <returns>ラベルに対応する要素。無ければnullを返す。</returns>
        public MySprite this[string key] {
            get {
                if (ContainsKey(key)) {
                    return list[key];
                } else {
                    return null;
                }
            }
        }

		public MySprite this[int index]
		{
			get
			{
				if (Count > index)
				{
					return list.Values[index - 1];
				}
				else
				{
					return null;
				}
			}
		}

        /// <summary>
        /// 指定したラベルが含まれているのかどうか
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool ContainsKey(string key) {
            return list.ContainsKey(key);
        }

        /// <summary>
        /// リストの末尾に要素を追加する。z座標が最大となる。
        /// </summary>
        /// <param name="key"></param>
        /// <param name="sprite"></param>
        public void Add(string key, MySprite sprite) {
            list.Add(key, sprite);
        }

        /// <summary>
        /// 指定したキーの要素を末尾の要素に持ってくる（z座標を最大にする）。
        /// </summary>
        /// <param name="key"></param>
        public void ShiftToLast(string key) {
            MySprite sprite = this[key];
            if (sprite != null) {
                int index = list.IndexOfKey(key);
                list.Add(key, sprite);
                list.RemoveAt(index);
            }
        }

        /// <summary>
        /// 指定したキーの要素を削除する。
        /// </summary>
        /// <param name="key"></param>
        public void Remove(string key) {
            list.Remove(key);
        }

        /// <summary>
        /// 要素を全てDisposeしつつ削除する。
        /// </summary>
        public void Clear() {
            foreach (MySprite s in list.Values) {
                s.Dispose();
            }
            list.Clear();
        }

        /// <summary>
        /// foreachの為の列挙の実装
        /// </summary>
        /// <returns></returns>
        public IEnumerator GetEnumerator() {
            for (int i = 0; i < list.Values.Count; i++) {
                yield return list.Values[i];
            }
        }


    }

}
